import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.RoundRectangle2D;

/*
* 游戏界面
* */
public class MainFrame extends JFrame{
    private int alevel = 2;//默认难度
    boolean finish;//是否完成
    private int tmp;//副界面传递临时变量
    //题目界面
    JFrame subFrame = new JFrame();//副窗口
    JButton[] numbers = new JButton[9];//用户可选择
    JButton[][] allgrid = new JButton[9][9];//题目显示

    private int[][] form1 = new int[20][20];//用来放置题目
    private int[][] form2 = new int[20][20];//用来辅助form1进行相关判断
    private int[][] form3 = new int[20][20];//再定义一个form3用来检验答案是否唯一
    private int[][] form4 = new int[20][20];//用来储存form1 的数据，用于重新开始菜单
    Initialize init = new Initialize();//初始化题目
    Dancing_link DL = new Dancing_link();//解题
    Check_puzzle ck = new Check_puzzle();//数独问题的随机生成
    private int i = 0, j = 0;
    //菜单栏
    //开始
    JMenuItem newGame = new JMenuItem("新游戏"),
            restart = new JMenuItem("重新开始"),
            //选项
            answer = new JMenuItem("揭晓答案");

    /*
    * 菜单
    */
    JMenu start = new JMenu("  开始  "),
            choose = new JMenu("  选项  "),
            level = new JMenu("  难度  ");

    /*菜单子项*/
    JCheckBoxMenuItem easy = new JCheckBoxMenuItem("简单");
    JCheckBoxMenuItem middle = new JCheckBoxMenuItem("中等");
    JCheckBoxMenuItem hard = new JCheckBoxMenuItem("困难");
    /*菜单条*/
    JMenuBar bar = new JMenuBar();
    public void creatMenu(){
        bar.setSize(200,300);
        //菜单栏
        bar.add(start);
        bar.add(choose);
        bar.add(level);
        //开始
        start.add(newGame);
        start.add(restart);
        //选项
        choose.add(answer);
        //难度
        level.add("简单");
        level.add("中等");
        level.add("困难");
        addMonitor();
    }
    public MainFrame(){
        //主窗口:题目
        JPanel puzzlePanel = new JPanel();
        puzzlePanel.setLayout(new GridLayout(9, 9));//设置布局GridLayout（9，9）
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                allgrid[x][y] = new JButton();//创建按键
                allgrid[x][y].setSize(35, 35);//设置按键大小
                allgrid[x][y].addActionListener(new LabelActionListener());//添加按键监听
                allgrid[x][y].setBorder(BorderFactory.createEtchedBorder());//添加按键边框效果
                allgrid[x][y].setFont(new Font("Dialog", Font.ITALIC, 25));//设置字体大小
                puzzlePanel.add(allgrid[x][y]);//添加按键到中间面板
            }
        }
        //改变中心面板背景颜色
        setColor();
        add(puzzlePanel, BorderLayout.CENTER);//添加题目面板到窗口中间
        //初始化题目按键
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                allgrid[i][j].setEnabled(true);//设置按键不可点击
            }
        }

        //副窗口(用户可选择)
        subFrame.setTitle("请选择");
        for (int k = 0; k < 9; k++) {//设置9个选择按键
            numbers[k] = new JButton("" + (k + 1));//设置按键显示为1~9
            numbers[k].setFont(new Font("Dialog", Font.ITALIC, 30));//设置按键上文字的字体属性
            numbers[k].addActionListener(new NumActionListener());//添加按键监听
            numbers[k].setForeground(Color.red); //设置按键前景色
            subFrame.add(numbers[k]);//添加按键到窗口
        }
        subFrame.setSize(120, 120);//设置副窗口大小
        subFrame.setLayout(new GridLayout(3, 3));//设置布局GridLayout（3，3）
        subFrame.setResizable(false);//设置副窗口大小不能更改

        //菜单栏
        creatMenu();//添加菜单只揭晓一个答案
        bar.setPreferredSize(new Dimension(-1, 30));//设置菜单条大小
        this.setJMenuBar(bar);//添加菜单条
    }

    private void setColor() {
        //centerPanel 区分九个九宫格
        BackgroudColor(3, 0, 5, 2);
        BackgroudColor(0, 3, 2, 5);
        BackgroudColor(6, 3, 8, 5);
        BackgroudColor(3, 6, 5, 8);
    }
    public void BackgroudColor(int x0,int y0,int x1,int y1){
        for (int i = x0; i <= x1; i++) {
            for (int j = y0; j <= y1; j++) {
                allgrid[i][j].setBackground(new Color(168, 168, 168));//RGB修改背景色
            }
        }
    }
    //设置题目按键可点击
    public void enableInput() {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                allgrid[i][j].setEnabled(true);//设置按键可点击
            }
        }
    }

    /**
     * 判断两数组是否相同,判定游戏是否胜利
     * @param a 数组a[][]
     * @param b	数组b[][]
     * @return boolean
     */
    public boolean isEqual(int[][] a, int[][] b) {
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= 9; j++) {
                if (a[i][j] == 0 || a[i][j] != b[i][j]) {
                    return false;
                }
            }
        }
        subFrame.setVisible(false);//副窗口不可见
        JOptionPane.showMessageDialog(null,
                "游戏结束！\nCONGRATULATIONS！");

        finish = true;//游戏完成
        return true;
    }

    public void set_puzzle() {
        for (int row = 1; row < 10; row++) {
            for (int column = 1; column < 10; column++) {
                allgrid[row - 1][column - 1].setForeground(Color.black);//设置按键前景色
                allgrid[row - 1][column - 1].setEnabled(true);//设置按键可点击
                if (form1[row][column] != 0) {
                    allgrid[row - 1][column - 1].setText("" + form1[row][column]);//若数组中位数字1~9，则在按键上显示为原数字
                } else {
                    allgrid[row - 1][column - 1].setText("");//若数组中位数字0，则在按键上显示为空
                }
                if (form1[row][column] != 0 ){//当数组中的数为零
                    allgrid[row - 1][column - 1].setForeground(Color.red);//设置按键前景色
                }
            }
        }
    }
    /**
     * 内部类用来添加 frame 中的每个按键的监听器
     */
    private class LabelActionListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            for (i = 0; i < 9; i++) {
                for (j = 0; j < 9; j++) {
                    if (!finish && e.getSource().equals(allgrid[i][j])) {
                        if(form4[i + 1][j + 1] == 0) {
                            for (int k = 0; k < 9; k++) {
                                if (ck.check(i + 1, j + 1, k + 1)) {//判断k是否符合数独规则
                                    numbers[k].setForeground(Color.red);//设置副界面中按键前景色
                                } else {
                                    numbers[k].setForeground(Color.black);//设置副界面中按键前景色
                                }
                                if (k + 1 == form1[i + 1][j + 1]) {
                                    numbers[k].setForeground(Color.red);//设置副界面中按键前景色
                                }
                            }
                            subFrame.setSize(50, 50);//设置每个按键大小
                            subFrame.setLocationRelativeTo(allgrid[i][j]);//使subFrame  相对于当前打开
                            subFrame.setVisible(true);//副窗口可见
                        }
                        /**
                         * 动画效果"打开 "
                         */
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e2) {
                            // TODO Auto-generated catch block
                            e2.printStackTrace();
                        }
                        int location = 1;
                        while (location < 5) {
                            try {
                                Thread.sleep(20);
                                subFrame.setSize(40 + 40 * location, 80 + 40 * location);
                                location++;
                            } catch (InterruptedException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                        }
                        return;
                    }
                }
            }
        }
    }

    /**
     * 内部类用来添加subframe中的每个按键的监听器
     */
    /**
     * 内部类用来添加subframe中的每个按键的监听器
     */
    public class NumActionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            for (int a = 0; a < 9; a++) {
                if (!finish && e.getSource().equals(numbers[a])) {
                    tmp = a + 1;//储存该位置的数值
                        if(form1[i + 1][j + 1] == tmp || !ck.check(i + 1, j + 1, tmp)) {//副界面再次点击，主界面数字清空
                        allgrid[i][j].setText("");//若数组中位数字0，则在按键上显示为空
                        allgrid[i][j].setForeground(Color.red);//设置按键前景色
                        form1[i + 1][j + 1] = form2[i + 1][j + 1] = 0;//对应form1和form4设为0
                    } else {
                        allgrid[i][j].setText("" + tmp);//显示用户填入的数字
                        allgrid[i][j].setForeground(Color.red);//设置按键前景色
                        form1[i + 1][j + 1] = form2[i + 1][j + 1] = tmp;//form1和form4设为点击的数值
                    }
                    if (isEqual(form1, form3));
                    ck.get_puzzle(form1);
                    i = j = tmp = 0;//使z复位
                    /**
                     * 填完后关闭子窗口,动画效果"关闭"
                     */
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e2) {
                        // TODO Auto-generated catch block
                        e2.printStackTrace();
                    }
                    int location = 1;
                    while (location < 5) {
                        try {
                            Thread.sleep(20);
                            subFrame.setSize(200 - 40 * location, 200 - 40 * location);
                            location++;
                        } catch (InterruptedException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }
                    }
                    subFrame.setVisible(false);//副窗口不可见
                    return;
                }
            }
        }
    }

    /**
     *  为菜单项添加监听器
     */
    public void addMonitor() {
        /**
         * 快速开始游戏
         */
        newGame.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                restart.setEnabled(true);//设置按键可点击
                finish = false;
                init.initialize(form1, form3, alevel);//根据游戏的难度等级初始化各题目数组
                ck.get_puzzle(form1);
                enableInput();//设置按键能点击
                for (int row = 1; row < 10; row++) {
                    for (int column = 1; column < 10; column++) {
                        form4[row][column] = form1[row][column];
                        if (form1[row][column] != 0) {
                            allgrid[row - 1][column - 1].setText("" + form1[row][column]);//若数组中位数字1~9，则在按键上显示为原数字
                            allgrid[row - 1][column - 1].setEnabled(true);//设置按键可点击
                            allgrid[row - 1][column - 1].setForeground(Color.BLACK);//设置按键前景色
                        } else {//当数组中的数为零
                            allgrid[row - 1][column - 1].setText("");//若数组中数字为0，则在按键上显示为空
                        }
                    }
                }
            }
        });
        restart.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {//当准备重新开始当前的题目时，输出提示是否确定继续
                Object[] options = {"OK", "Cancel"};
                int returnVal = JOptionPane.showOptionDialog(null, "你确定要重新开始吗?", "重新游戏",
                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
                if (returnVal != JOptionPane.OK_OPTION) {
                    return;
                }
                finish = false;
                //重新开始游戏
                for (int row = 1; row < 10; row++) {
                    for (int column = 1; column < 10; column++) {
                        form1[row][column] = form4[row][column];//数组答案给数组题目
                        if (form1[row][column] != 0) {
                            allgrid[row - 1][column - 1].setText("" + form1[row][column]);//若数组中位数字1~9，则在按键上显示为原数字
                        } else {//当数组中的数为零
                            allgrid[row - 1][column - 1].setText("");//若数组中位数字0，则在按键上显示为空
                        }
                    }
                }
            }
        });
        /**
         * 智能解当前题目
         */
        answer.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                finish = true;

                int k=DL.calsudoku(form1, false);
                set_puzzle();
            }
        });
        easy.addActionListener(new ActionListener() {//游戏难度为简单的监听器
            public void actionPerformed(ActionEvent e) {
                alevel = 1;//设置游戏难度等级为1
                easy.setState(true);//多选框状态
                middle.setState(false);
                hard.setState(false);
            }
        });
        middle.addActionListener(new ActionListener() {//游戏难度为中等的监听器
            public void actionPerformed(ActionEvent e) {
                alevel = 2;//设置游戏难度等级为2
                easy.setState(false);//多选框状态
                middle.setState(true);
                hard.setState(false);
            }
        });
        hard.addActionListener(new ActionListener() {//游戏难度为困难的监听器
            public void actionPerformed(ActionEvent e) {
                alevel = 3;//设置游戏难度等级为3
                easy.setState(false);//多选框状态
                middle.setState(false);
                hard.setState(true);
            }
        });


    }








    public static void main(String[] args) {
        MainFrame frame = new MainFrame();
        int width = Toolkit.getDefaultToolkit().getScreenSize().width;//获取屏幕宽度
        int height = Toolkit.getDefaultToolkit().getScreenSize().height;//获取屏幕高度
        frame.setTitle("数独");
        frame.setLocation(width/2-300,height/2-350);
        frame.setSize(850,800);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {//窗口关闭的监听器
            @Override
            public void windowClosing(WindowEvent e) {
                Object[] options = { "确定", "取消" };
                int returnVal = JOptionPane.showOptionDialog(null, "确定要退出游戏？", "Warning",
                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
                        null, options, options[1]);
                if(returnVal == JOptionPane.OK_OPTION)
                    System.exit(0);
            }
        });
    }


}
